package cz.vse.adventura.po1715.xburj54_bursa.gui;

import java.awt.Dimension;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.Date;
import javax.swing.JFileChooser;

/*******************************************************************************
 * Instance třídy {@code ActivityLog} představují soubor, který zajišťuje
 *      záznam průběhu hry
 *
 * @author    Jan Bursa
 * @version   1.01
 */
public class ActivityLog {
//== KONSTANTNÍ ATRIBUTY TŘÍDY =================================================
    
    /** Formátování časového údaje - očekává jediný parametr. */
    private static final String FORMÁT_ČASU =
        "%tF - %<tT:";

    
//== PROMĚNNÉ ATRIBUTY TŘÍDY ===================================================
//== STATICKÝ INICIALIZAČNÍ BLOK - STATICKÝ KONSTRUKTOR ========================
//== KONSTANTNÍ ATRIBUTY INSTANCÍ ==============================================
    
    /** GUI, pro které tato instance pracuje. */
    private final GUI_04 gui;
    
    /** Rozměry okna */
    private final Dimension LOG_WINDOW_SIZE = new Dimension(330,200);
    
    /** Okno */
    private final ActivityLogWindow logWindow;
    
    
//== PROMĚNNÉ ATRIBUTY INSTANCÍ ================================================
    
    /** True, pokud se má dělat záznam do okna */
    private Boolean boolWindowVisible = false;

    /** True, pokud se má dělat záznam do okna */
    private Boolean boolRecorded = true;
    
    /** True, pokud se má zaznamenávat do souboru */
    private Boolean boolInFile = false;
    
    /** Soubor, do kterého se bude zapisovat */
    private File logFile = null;
    
    /** Výstupní proud ukládající žurnál */
    private Writer fileWriterOutput;    
    
//== PŘÍSTUPOVÉ METODY VLASTNOSTÍ TŘÍDY ========================================
//== OSTATNÍ NESOUKROMÉ METODY TŘÍDY ===========================================

//##############################################################################
//== KONSTRUKTORY A TOVÁRNÍ METODY =============================================
    /***************************************************************************
     *
     */
    public ActivityLog(GUI_04 gui) {
        this.gui = gui;
        logWindow = new ActivityLogWindow(LOG_WINDOW_SIZE);
        logWindow.setVisible(boolWindowVisible);
    }
    
//== ABSTRAKTNÍ METODY =========================================================
//== PŘÍSTUPOVÉ METODY VLASTNOSTÍ INSTANCÍ =====================================
    
    /***************************************************************************
     * Vrací true, pokud má být okno viditelné
     * @return viditelnost
     */
    Boolean isLogWindowVisible() {
        return logWindow.isVisible();
    }

    /***************************************************************************
     * Vrací true, pokud má být okno logu viditelné
     * @param visible - viditelnost
     */
    void setLogWindowVisible(Boolean visible) {
        logWindow.setVisible(visible);
    }

    /***************************************************************************
     * Zjistí stav zapisování záznamu
     * @return stav - boolean
     */
    boolean isRecorded() {
        return boolRecorded;
    }

    /***************************************************************************
     * Nastaví zapisování do okna
     * @param recorded - true/false
     */
    void setRecorded(Boolean recorded) {
        boolRecorded = recorded;
        if(boolRecorded) {
            logWindow.update(startingLine());
        } else {
            logWindow.update(stoppingLine());
        }
    }
            
    /***************************************************************************
     * Zjistí stav zapisování záznamu do okna
     * @return stav - boolean
     */
    boolean getRecordInWindow() {
        return boolWindowVisible;
    }
    
    /***************************************************************************
     * Nastaví zapisování do okna
     * @param inWindow - true/false
     */
    void setRecordInWindow(Boolean inWindow) {
        boolWindowVisible = inWindow;
        logWindow.setVisible(inWindow);
        if(boolWindowVisible) {
            logWindow.update(startingLine());
        } else {
            logWindow.update(stoppingLine());
        }
    }
        
    /***************************************************************************
     * Zjistí stav zapisování do souboru
     * @return stav - boolean
     */
    boolean getRecordInFile() {
        return boolInFile;
    }
    
    /***************************************************************************
     * Nastaví zapisování do souboru
     * @param inFile - true/false
     * @return výsledek - když uživatel nevybere soubor, vrací false
     */
    Boolean setRecordInFile(Boolean inFile) {
        boolInFile = inFile;
        if(boolInFile) {
            if(logFile == null)  {
                chooseLogFile();
            }
            if(logFile == null) {  //Soubor nebyl zadán
                boolInFile = false;
                return false;
            } else {
                try {
                    fileWriterOutput = new FileWriter(logFile, true);
                    fileWriterOutput.write(startingLine());
                    fileWriterOutput.flush();
                } catch(IOException exc) {
                    throw new RuntimeException(
                        "\nNepodařilo se otevřít soubor", exc);
                }
                return true;
            }
        } else {

            try{
                fileWriterOutput.write(stoppingLine());
            } catch(IOException exc){
                throw new RuntimeException(
                    "\nNepodařilo se zapsat ukončení žurnálu", exc);
            }
            closeOutput();
            return true;
        }
    }
    
       
//== OSTATNÍ NESOUKROMÉ METODY INSTANCÍ ========================================
    
    /***************************************************************************
     * Vytvoří záznam příkazu do okna a/nebo do souboru
     * 
     * @param command - příkaz, který se má zaznamenat
     */
    void recordCommand(String command) {
        if(boolRecorded) {
            Date time = new Date();
            String line;
            if(command.equalsIgnoreCase("")) {
                line = String.format("%s\n" + FORMÁT_ČASU + "%s\n%s\n",
                        "----------------------------------------------",
                        time, "Začátek hry",
                        "----------------------------------------------");
            } else {
                line = String.format(FORMÁT_ČASU + "  %s\n", time, command);
            }
            logWindow.update(line);
            if(boolInFile) {
                updateFile(line);
            }
        }
    }
    
    /***************************************************************************
     * Nastaví soubor, do kterého se zapisuje 
     * Požádá uživatele, aby ho vybral
     */
    void chooseLogFile() {
        final JFileChooser fc = new JFileChooser();
        //Vynuluje logFile pro případ, že by uživatel nic nezadal
        logFile = null;
        int ret = fc.showOpenDialog(gui.getAppWindow());
        if (ret == JFileChooser.APPROVE_OPTION) {
            //Pokud uživatel něco zadal, zloží informaci do proměnné žSoubor
            logFile = fc.getSelectedFile();
        }
    }
    
//== SOUKROMÉ A POMOCNÉ METODY TŘÍDY ===========================================
//== SOUKROMÉ A POMOCNÉ METODY INSTANCÍ ========================================
    
    /***************************************************************************
     * Připojí řádek záznamu na konec výstupního souboru
     * 
     * @param line - řádek, který se připojí
     */
    private void updateFile(String line) {
        try {
                fileWriterOutput.write(line);;
                fileWriterOutput.flush();
            } catch(IOException exc) {
                throw new RuntimeException(
                    "\nChyba při výstupu do souboru " + fileWriterOutput, exc);
            }             
    }
    
    /***************************************************************************
     * Oznámí začátek zápisu  
     */
    private String startingLine() {
        return String.format(FORMÁT_ČASU + "  %s\n", new Date(), "Zahájen záznam aktivit");        
    }
    
    /***************************************************************************
     * Oznámí konec zápisu
     */
    private String stoppingLine() {
        return String.format(FORMÁT_ČASU + "  %s\n", new Date(), "Ukončen záznam aktivit");        
    }
    
    /***************************************************************************
     * Uzavře soubor 
     */
    private void closeOutput() {
        if(fileWriterOutput != null) {
            try {
                fileWriterOutput.close();
            } catch(IOException exc) {
                throw new RuntimeException(
                    "\nSoubor " + fileWriterOutput +
                    " se žurnálem se nepodařilo zavřít", exc);
            }
        }
    }
    
//== INTERNÍ DATOVÉ TYPY =======================================================
//== TESTY A METODA MAIN =======================================================
//
//    /***************************************************************************
//     * Testovací metoda.
//     */
//    public static void test()
//    {
//        ActivityLog inst = new ActivityLog();
//    }
//    public static void main( String[] args )  {  test();  }

    
}
